import sys
import os
import xlrd
import xlwt
import csv

import asyncio
import time
import ctypes
import inspect
# from PySide6 import QtWidgets
# from PySide2 import QtWidgets

from PyQt5.QtWidgets import QWidget,QMessageBox,QFileDialog,QHeaderView,QTableWidgetItem,QAbstractItemView,QMenu
from PyQt5.QtCore import pyqtSlot,pyqtSignal,QThread,QPropertyAnimation,QEasingCurve,QRect,Qt,QPoint
from PyQt5.QtGui import QBrush,QColor,QPainter,QPen
from PyQt5 import QtCore, QtGui, QtWidgets
from qt_material import apply_stylesheet

from PIL import Image
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains

from io import BytesIO
#import sys
import subprocess
#from pathlib import Path as pathdir
#from win32com.client import Dispatch
import psutil
import zipfile
import requests
import base64
import re
import threading
import configparser


from ui import Ui_Form,Ui_Form_1
import fateadm_api
import myselenium
from config import setting


class UsingTest_1(QWidget, Ui_Form_1):
    def __init__(self, parent):
        super(UsingTest_1, self).__init__()
        self.setupUi(self)
        self.center()
        self.parent = parent
        self.setWindowFlags(self.windowFlags() |Qt.FramelessWindowHint)
        self.setFixedSize(self.width(), self.height())
        self.animation = QPropertyAnimation(self, b'windowOpacity')
        self.animation.setDuration(500)
        self.parent.thread.logsing.connect(lambda : self.on_click(3))
        self.radioButton_0.clicked.connect(lambda : self.on_click(2))
        self.pushButton.clicked.connect(lambda : self.on_click(1))
        try:
            self.animation.finished.disconnect(self.close)
        except:
            pass
        self.animation_call(0,1)
        self.setContentsMargins(0, 0, 0, 0)
        self.title = QtWidgets.QLabel("My Own Bar")
        #self.title.setFixedHeight(35)
        #self.title.setAlignment(Qt.AlignCenter)
        self.start = QPoint(0, 0)
        self.pressing = False

    def paintEvent(self, event):
        super(UsingTest_1, self).paintEvent(event)
        painter = QPainter(self)
        painter.setPen(QPen(QColor(255, 0, 0, 90), 2))
        painter.drawRect(self.rect())

    def resizeEvent(self, QResizeEvent):
        super(UsingTest_1, self).resizeEvent(QResizeEvent)
        self.title.setFixedWidth(self.width())

    def mousePressEvent(self, event):
        self.start = self.mapToGlobal(event.pos())
        self.pressing = True

    def mouseMoveEvent(self, event):
        if self.pressing:
            self.end = self.mapToGlobal(event.pos())
            self.movement = self.end-self.start
            self.setGeometry(self.mapToGlobal(self.movement).x(),
                                self.mapToGlobal(self.movement).y(),
                                self.width(),
                                self.height())
            self.start = self.end

    def mouseReleaseEvent(self, QMouseEvent):
        self.pressing = False

    def center(self):
        screen=QtWidgets.QDesktopWidget().screenGeometry()
        size=self.geometry()
        self.move((screen.width()-size.width())/2,(screen.height()-size.height())/2)

    def animation_call(self,v1,v2):
        self.animation.stop()
        if v1:
            self.animation.finished.connect(self.close)
        self.animation.setStartValue(v1)
        self.animation.setEndValue(v2)
        self.animation.start()

    @pyqtSlot()
    def on_click(self,mid):
        if mid == 1:
            self.pushButton.setText("导出中")
            self.pushButton.setEnabled(False)
            ox = self.comboBox.currentIndex()
            def ead(ap,o):
                data = ["","","","","","","",""]
                for i in range(0,8):
                    itm = self.parent.tableWidget.item(o,i)
                    if itm:
                        data[i] = itm.text()
                ap.append(data)
            apps = []
            removeapps = []
            for i in range(0,self.parent.tableWidget.rowCount()):
                mitem = self.parent.tableWidget.item(i,4)
                if ox == 0 and mitem:
                    if mitem.text() == "完成":
                        ead(apps,i)
                        removeapps.append(i)
                elif ox == 1 and mitem:
                    if mitem.text() == "失败":
                        ead(apps,i)
                        removeapps.append(i)
                elif ox == 2 and not mitem:
                    ead(apps,i)
                    removeapps.append(i)
            sss = ["已完成","已失败","未开始"]
            print(apps)
            if self.radioButton_3.isChecked():
                self.parent.thread.my_call(xls_save,os.path.join(setting.mypath,sss[ox] + "-" + str(int(time.time())) + ".xls"),apps)
            elif self.radioButton_2.isChecked():
                self.parent.thread.my_call(txt_save,os.path.join(setting.mypath,sss[ox] + "-" + str(int(time.time())) + ".txt"),apps)
            elif self.radioButton.isChecked():
                self.parent.thread.my_call(csv_save,os.path.join(setting.mypath,sss[ox] + "-" + str(int(time.time())) + ".csv"),apps)
            sn = 0
            for rem in removeapps:
                self.parent.tableWidget.removeRow(rem-sn)
                sn += 1
        elif mid == 2:
            self.animation_call(1,0)
        elif mid == 3:
            self.pushButton.setText("导出")
            self.pushButton.setEnabled(True)


class UsingTest(QWidget, Ui_Form):
    def __init__(self, *args, **kwargs):
        super(UsingTest, self).__init__(*args, **kwargs)
        self.setupUi(self) 

        #self.pushButton_3.setToolTip("显示")
        self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        #self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.textEdit.setReadOnly(True)

        self.pushButton_2.clicked.connect(lambda : self.on_click(1))
        self.pushButton_3.clicked.connect(lambda : self.on_click(2))
        self.pushButton_4.clicked.connect(lambda : self.on_click(3))
        self.pushButton_5.clicked.connect(lambda : self.on_click(4))
        self.pushButton_7.clicked.connect(lambda : self.on_click(5))
        self.pushButton_9.clicked.connect(lambda : self.on_click(6))
        self.pushButton_110.clicked.connect(lambda : self.on_click(7))

        self.comboBox.currentTextChanged.connect(lambda : self.on_comboBox(1))
        self.comboBox_2.currentTextChanged.connect(lambda : self.on_comboBox(2))
        self.comboBox_2.setCurrentIndex(int(setting.webshow))
        self.comboBox.setCurrentIndex(int(setting.callsum))


        self.thread = pyqt_thread()
        self.thread.logsing.connect(self.log_txt)
        self.thread.worksing.connect(self.set_work)
        self.thread.start()
        self.setAcceptDrops(True)
        self.center()

        self._contextMenu = QMenu(self)
        self._contextMenu.addAction('此行启动', lambda : self.m_delete(1))
        self._contextMenu.addAction('删除此行', lambda : self.m_delete(2))
        self._contextMenu.addAction('清空所有', lambda : self.m_delete(3))
        self._animation = QPropertyAnimation(self._contextMenu, b'geometry', self,easingCurve=QEasingCurve.Linear, duration=300)
        self._animation_2 = QPropertyAnimation(self.tableWidget, b'geometry', self,easingCurve=QEasingCurve.Linear, duration=300)
        self._animation_3 = QPropertyAnimation(self.textEdit, b'geometry', self,easingCurve=QEasingCurve.Linear, duration=300)
        self._contextMenu.setStyleSheet("font: 12pt \"楷体\";")
        self.dic_b = {}
        self.bili = {}

    def center(self):
        screen=QtWidgets.QDesktopWidget().screenGeometry()
        size=self.geometry()
        self.move((screen.width()-size.width())/2,(screen.height()-size.height())/2)

    #def resizeEvent(self, QResizeEvent):
    #    if not self.bili:
    #        self.bili.update({"t_w":self.textEdit.width()/self.width(),"t_h":self.textEdit.height()/self.height(),"x":self.textEdit.x()/self.x(),"y":self.textEdit.y()/self.y()})
    #    print(self.textEdit.width(),self.textEdit.height(),self.width(),self.height())
    #    self.dic_button.update({"textEdit-width":self.width()*self.bili["t_w"],"textEdit-height":self.height()*self.bili["t_h"]})

    def dragEnterEvent(self,event):
        if self.pushButton_4.text() == "加载文件":
            file = event.mimeData().text()
            file_list = file.split("file:///")
            for i in file_list:
                if i:
                    self.thread.my_call(open_work,i.replace("\n",""))
            self.pushButton_4.setText("加载中")

    def closeEvent(self, event):
        ret = My_QMessageBox("关闭","确定关闭吗?")
        if ret:
            event.accept()
            self.close()
        else:
            event.ignore()

    def contextMenuEvent(self, event):
        if self.tableWidget.selectedItems() and self.pushButton_7.text() == "启动":
            pos = event.globalPos()
            size = self._contextMenu.sizeHint()
            self.my_show(pos,self._animation,False,size.width(), size.height())
            self._contextMenu.exec_(event.globalPos())

    @pyqtSlot()
    def on_comboBox(self,mid):
        if mid == 1:
            setting.set_cfg("db", "callsum", str(self.comboBox.currentIndex()))
        elif mid == 2:
            setting.set_cfg("db", "webshow", str(self.comboBox_2.currentIndex()))

    @pyqtSlot()
    def on_click(self,mid):
        if mid == 1:
            if self.pushButton_2.text() == "关闭日志":
                self.dic_b.update({"E-w":self.textEdit.width(),"E-h":self.textEdit.height()})
                self.my_show(self.textEdit,self._animation_3,True,self.dic_b["E-w"],self.dic_b["E-h"])
                self.pushButton_2.setText("打开日志")
                self.textEdit.setVisible(False)
            else:
                self.pushButton_2.setText("关闭日志")
                self.my_show(self.textEdit,self._animation_3,False,self.dic_b["E-w"],self.dic_b["E-h"])
                self.textEdit.setVisible(True)
                self.resize(self.width(), self.height())
        elif mid == 2:
            if self.pushButton_3.text() == "关闭表格":
                self.tableWidget.setVisible(False)
                self.dic_b.update({"W-w":self.tableWidget.width(),"W-h":self.tableWidget.height()})
                self.my_show(self.tableWidget,self._animation_2,True,self.dic_b["W-w"],self.dic_b["W-h"])
                self.pushButton_3.setText("打开表格")
            else:
                self.tableWidget.setVisible(True)
                self.pushButton_3.setText("关闭表格")
                self.my_show(self.tableWidget,self._animation_2,False,self.dic_b["W-w"],self.dic_b["W-h"])
                self.resize(self.width(), self.height())
        elif mid == 3:
            self.pushButton_4.setEnabled(False)
            fname = QFileDialog.getOpenFileName(self, 'Open file', filter='File(*.xls *.xlsx *.csv)')
            if fname[0]:
                self.thread.my_call(open_work,fname[0])
                self.pushButton_4.setText("加载中")
            else:
                self.pushButton_4.setEnabled(True)
 
        elif mid == 4:
            self.mwin = UsingTest_1(self)
            self.mwin.show()
        elif mid == 5:
            if self.pushButton_7.text() == "启动":
                dic = {}
                dic.update({"webshow":self.comboBox_2.currentIndex()})
                dic.update({"category":self.comboBox_3.currentIndex()})
                dic.update({"call":self.get_run_data})
                m_dic = get_call_data(self.comboBox.currentIndex()+1,self.tableWidget.rowCount())
                dic.update({"sum":m_dic})
                self.thread.my_call(run_main,dic)
                self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
                self.pushButton_7.setText("停止")
            else:
                ret = My_QMessageBox("停止","确定停止吗吗?")
                if ret:
                    #stop_main(0,1)
                    ret = self.thread.my_call(stop_main)
                    self.pushButton_7.setText("停止中")
                    #if not ret:
                    #    self.pushButton_7.setText("启动")
                    #    self.tableWidget.setEditTriggers(QAbstractItemView.DoubleClicked)
        elif mid == 6:
            if self.pushButton_9.text() == "初始化":
                try:
                    setting.add_section("db")
                except:
                    pass
                setting.set_cfg("db", "chromedriver", "")
                setting.set_cfg("db", "chrome_path", "")
                setting.set_cfg("db", "webshow", str(self.comboBox_2.currentIndex()))
                setting.set_cfg("db", "callsum", str(self.comboBox_3.currentIndex()))
                setting.set_cfg("db", "validation", "feiwen")
                setting.set_cfg("db", "rotating", "1")
                self.pushButton_9.setText("初始化中")
                self.pushButton_7.setEnabled(False)
                self.textEdit.clear()
                self.thread.my_call(myselenium.chrome_init_)
        elif mid == 7:
            self.textEdit.clear()

    def m_delete(self,mid):
        if mid == 1:
            dic = {}
            dic.update({"webshow":self.comboBox_2.currentIndex()})
            dic.update({"category":self.comboBox_3.currentIndex()})
            dic.update({"call":self.get_run_data})
            m_dic = get_call_data(self.comboBox.currentIndex()+1,self.tableWidget.rowCount(),sta=self.tableWidget.currentRow())
            dic.update({"sum":m_dic})
            self.thread.my_call(run_main,dic)
            self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
            self.pushButton_7.setText("停止")
        elif mid == 2:
            self.tableWidget.removeRow(self.tableWidget.currentRow())
        elif mid == 3:
            while self.tableWidget.rowCount():
                self.tableWidget.removeRow(0)

    def my_show(self,buttn,animation,ism, w, h):
        x, y = buttn.x(), buttn.y()
        animation.stop()
        if not ism:
            animation.setStartValue(QRect(x, y, 0, 0))
            animation.setEndValue(QRect(x, y, w, h))
        else:
            animation.setStartValue(QRect(x, y, w, h))
            animation.setEndValue(QRect(x, y, 0, 0))
        animation.start()

    def set_work(self,dic):
        if dic['type'] == 'update':
            row = self.tableWidget.rowCount()
            self.tableWidget.insertRow(row)
            self.tableWidget.setItem(row,0,QTableWidgetItem(dic['name']))
            self.tableWidget.setItem(row,1,QTableWidgetItem(dic['old']))
            if dic['new']:
                self.tableWidget.setItem(row,2,QTableWidgetItem(dic['new']))
        elif dic['type'] == 'successful':
            item = QTableWidgetItem(dic['code'])
            item.setForeground(QBrush(QColor(0,255,0)))
            self.tableWidget.setItem(dic['id'],4,item)
            self.tableWidget.setItem(dic['id'],3,QTableWidgetItem(dic['category']))
            self.tableWidget.setItem(dic['id'],6,QTableWidgetItem(time.strftime("%Y-%m-%d %H:%M:%S")))
        elif dic['type'] == 'failure':
            item = QTableWidgetItem(dic['code'])
            item.setForeground(QBrush(QColor(255,0,0)))
            self.tableWidget.setItem(dic['id'],4,item)
            self.tableWidget.setItem(dic['id'],3,QTableWidgetItem(dic['category']))
            self.tableWidget.setItem(dic['id'],5,QTableWidgetItem(dic['msg']))
        elif dic['type'] == 'burek':
            self.tableWidget.setItem(dic['id'],7,QTableWidgetItem(dic['msg']))
        elif dic['type'] == 'complete':
            self.pushButton_4.setText("加载文件")
            self.pushButton_4.setEnabled(True)
        elif dic['type'] == 'init':
            self.pushButton_9.setText("初始化")
            self.pushButton_7.setEnabled(True)
        elif dic['type'] == 'button':
            if dic['id'] in setting.call_dict:
                setting.call_dict.pop(dic['id'])
            if not setting.call_dict:
                self.pushButton_7.setText("启动")
                self.tableWidget.setEditTriggers(QAbstractItemView.DoubleClicked)

    def log_txt(self,txt):
        self.textEdit.append(time.strftime("%Y-%m-%d %H:%M:%S") + " " + txt)

    def get_run_data(self,num):
        data = ["","",""]
        for i in range(0,3):
            itm = self.tableWidget.item(num,i)
            if itm:
                data[i] = itm.text()
        return data


def My_QMessageBox(code,codes):
    mesBox = QMessageBox()
    mesBox.setWindowTitle(code)
    #mesBox.setWindowFlags(Qt.WindowMinimizeButtonHint)
    mesBox.setText(codes)
    mesBox.setIcon(QMessageBox.Information)
    yes = mesBox.addButton("是", QMessageBox.YesRole)
    mesBox.addButton("否", QMessageBox.NoRole)
    mesBox.setStyleSheet("font: 12pt \"楷体\";")
    mesBox.exec_()
    if mesBox.clickedButton() == yes:
        return True
    return False


def get_call_data(cd,sum,sta=0):
    dic = {str(i):[] for i in range(0,cd)}
    data = [i for i in range(sta,sum)]
    while data:
        for i in dic:
            dic[i].append(data[0])
            data.remove(data[0])
            if not data:
                break
    return dic


class pyqt_thread(QThread):
    logsing = pyqtSignal(str)
    worksing = pyqtSignal(dict)
    def __init__(self):
        super(pyqt_thread, self).__init__()
        self.daemon = True
        self.loop = asyncio.new_event_loop()
        self.run_dict = {}

    def run(self):
        self.loop.run_forever()

    def my_call(self,call,*kavy):
        asyncio.run_coroutine_threadsafe(call(self.logsing,self.worksing,*kavy),self.loop)

    def add_async_call(self,call,id,dic):
        _async = asyncio.run_coroutine_threadsafe(call(self.logsing,self.worksing,id,dic),self.loop)
        self.run_dict.update({id:_async})

    def async_stop(self):
        for idm in self.run_dict:
            self.run_dict[idm].cancel()
        self.run_dict = {}


async def open_work(logsing,worksing,path):
    try:
        if path[-3:] == "xls" or path[-4:] == "xlsx":
            workbook = xlrd.open_workbook(path)
            table = workbook.sheet_by_name("Sheet1")
            for m in range(0,table.nrows):
                dic = {"type":"update","name":table.row_values(m)[0],"old":table.row_values(m)[1],"new":""}
                if table.ncols >= 3:
                    dic.update({"new":table.row_values(m)[2]})
                worksing.emit(dic)
        elif path[-3:] == "csv":
            csvfile = open(path,newline='')
            spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
            for row in spamreader:
                row = row[0].split(",")
                dic = {"type":"update","name":row[0],"old":row[1],"new":""}
                if len(row) >= 3:
                    dic.update({"new":row[2]})
                worksing.emit(dic)
    except Exception as e:
        logsing.emit("加载文件失败 || " + str(e.args))
    worksing.emit({"type":"complete"})


async def run_main(logsing,worksing,dic):
    logsing.emit("任务 " + str(dic["category"]) + " 启动数量 " + str(len(dic['sum'])) + " 界面 " + str(dic["webshow"]))
    for i in dic['sum']:
        setting.call_dict.update({i:myselenium.workbok(dic['call'],dic['sum'][i],dic["category"],dic["webshow"],i,logsing,worksing)})
    for r in setting.call_dict:
        setting.call_dict[r].start()


async def stop_main(logsing,worksing):
    def _async_raise(tid, exctype):
        try:
            tid = ctypes.c_long(tid)
            if not inspect.isclass(exctype):
                exctype = type(exctype)
            res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
            if res == 0:
                raise ValueError("invalid thread id")
            elif res != 1:
                # if it returns a number greater than one, you're in trouble,
                # and you should call it again with exc=NULL to revert the effect
                ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
                raise SystemError("PyThreadState_SetAsyncExc failed")
        except Exception as err:
           logsing.emit(str(err.args))
    for ca in setting.call_dict:
        setting.call_dict[ca].chrome.myquit()
        #_async_raise(myselenium.setting.call_dict[ca].ident, SystemExit)
    myselenium.getpid("chromedriver.exe",False)
    #for r in myselenium.setting.call_dict:
    #    if myselenium.setting.call_dict[r]:
    #        print(myselenium.setting.call_dict[r].isAlive())


async def xls_save(logsing,worksing,name,data):
    workbook = xlwt.Workbook()
    sheet = workbook.add_sheet('Sheet1')
    for index, value in enumerate(data):
        for it,iv in enumerate(value):
            sheet.write(index, it, iv)
    workbook.save(name)
    logsing.emit("导出完成")


async def txt_save(logsing,worksing,name,data):
    with open(name ,"w",encoding="utf-8") as efile:
        for tx in data:
            efile.write(" ".join(tx) + "\n")
    logsing.emit("导出完成")


async def csv_save(logsing,worksing,name,data):
    with open(name, 'w', newline='') as csvfile:
        spamwriter = csv.writer(csvfile, delimiter=',')
        for index, value in enumerate(data):
            spamwriter.writerow(value)
    logsing.emit("导出完成")


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    apply_stylesheet(app, theme='light_blue.xml')
    win = UsingTest()
    win.show()
    sys.exit(app.exec_())

